﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Datorgrafik_lab2.Helpers;

namespace Datorgrafik_lab2.Objects {
    class Ground : GameObject {
        public static int numRow = 100;
        public static int numCol = 100;
        public static int radius = 100;    

        Color[] colorData;
        double pixelHeightDistance;
        double pixelWidthDistance;

        public Ground(GraphicsDevice graphics, Vector3 pos, float scale, Texture2D texture)
            : base(graphics, pos, Quaternion.Identity, scale, texture)
        {}

        /// <summary>
        /// This function calculates the height value
        /// </summary>
        public float CalculateZ(float x, float y)
        {
            double pixelHeightDistance = (double)this.texture.Height / Ground.numRow;
            double pixelWidthDistance = (double)this.texture.Width / (Ground.numCol + 1);

            int colorIndex =
                        (int)((double)y * pixelHeightDistance) * this.texture.Width
                        + (int)((double)x * pixelWidthDistance);

            // Minus otherwise the mountains will be inverted.
            return (float)(-RGB2HSL.ToHSL(colorData[colorIndex]).H / 50);    
        }

        public Vector3 GetSphereCords(Vector3 pos)
        {
            int yMax = numRow - 1;
            int xMax = numCol - 1;

            double ringradius = (float)((CalculateZ(pos.X, pos.Y) + radius) * Math.Sin(pos.Y * Math.PI / yMax));

            return new Vector3(
                (float)(Math.Cos((xMax - pos.X) * Math.PI * 2.0f / xMax) * ringradius),
                (float)(Math.Cos(pos.Y * Math.PI / yMax) * radius),
                (float)(Math.Sin((xMax - pos.X) * Math.PI * 2.0f / xMax) * ringradius));
        }

        protected override void InitializeModel() {
            this.colorData = new Color[this.texture.Height * this.texture.Width];
            this.texture.GetData<Color>(colorData);

            pixelHeightDistance = (double)this.texture.Height / Ground.numRow;
            pixelWidthDistance = (double)this.texture.Width / (Ground.numCol + 1);

            initializeGround();
        }

        private void initializeGround() {
            initializeVertices();

            initializeIndices();
        }

        private void initializeVertices() {
            vertices = new VertexPositionColorTexture[numRow * numCol];

            this.colorData = new Color[this.texture.Height * this.texture.Width];
            this.texture.GetData<Color>(this.colorData);

            int posXshift = 0;//numCol / 2;
            int posZshift = 0;// numRow / 2;

            int yMax = numRow-1;
            int xMax = numCol-1;
            
            for(int row = 0; row < numRow; row++) {
                for(int col = 0; col < numCol; col++) {
                    int colorIndex =
                        (int)((double)row * pixelHeightDistance) * this.texture.Width
                        + (int)((double)col * pixelWidthDistance);                   

                    float height = (float)(-RGB2HSL.ToHSL(colorData[colorIndex]).H/50);

                    double ringradius = (float)((height + radius) * Math.Sin(row * Math.PI / yMax));

                    Vector3 xyz = new Vector3(
                        (float)(Math.Cos((xMax - col) * Math.PI * 2.0f / xMax) * ringradius),
                        (float)(Math.Cos(row * Math.PI / yMax) * radius),
                        (float)(Math.Sin((xMax - col) * Math.PI * 2.0f / xMax) * ringradius));      
                    
                    //Set position to a plane
                    Vector3 position = new Vector3(
                        (float)(col - posXshift),                                             
                        height,
                        (float)(row - posZshift)
                        );

                    //CSwitch between plane or sphere
                    position = xyz;

                    this.vertices[(row * numCol) + col] = new VertexPositionColorTexture(
                        position, 
                        Color.White,
                        new Vector2((float)col / (numCol-1), (float)row / (numRow-1)));
                }
            }
        }

        private void initializeIndices() {
            //6 vertices make up 2 triangles. Not decreasing Col because we want it to wrap around
            indices = new int[(numRow) * (numCol) * 6];

            int counter = 0;

            //Indices
            for(int row = 0; row < numRow - 1; row++) {
                for(int col = 0; col < numCol - 1; col++) {
                    int topLeft = (row * numCol) + col;
                    int topRight = (row * numCol) + col+1;
                    int bottomLeft = ((row + 1) * numCol) + col;
                    int bottomRight = ((row + 1) * numCol) + col+1;                            

                    indices[counter++] = topLeft;
                    indices[counter++] = topRight;
                    indices[counter++] = bottomLeft;

                    indices[counter++] = topRight;
                    indices[counter++] = bottomRight;
                    indices[counter++] = bottomLeft;                    
                }
            }
        }
    }
}